using AutoMapper;
using MediatR;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using System;
using System.IO;
using WMS.Api.Application.Commands;
using WMS.Common;
using WMS.Domain;
using WMS.Infrastructure;

namespace WMS.Api.Application.CommandHandlers
{
    /// <summary>
    /// 获取入库类型列表命令处理程序
    /// </summary>
    public class GetInboundTypeListCommandHandler : IRequestHandler<GetInboundTypeListCommand, ApiResult<List<InboundTypeDto>>>
    {
        private readonly MyDBContext _dbContext;
        private readonly IMapper _mapper;
        private readonly ILogger<GetInboundTypeListCommandHandler> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="mapper">对象映射器</param>
        /// <param name="logger">日志记录器</param>
        public GetInboundTypeListCommandHandler(MyDBContext dbContext, IMapper mapper, ILogger<GetInboundTypeListCommandHandler> logger)
        {
            _dbContext = dbContext;
            _mapper = mapper;
            _logger = logger;
        }

        /// <summary>
        /// 处理获取入库类型列表命令
        /// </summary>
        /// <param name="request">请求命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>入库类型列表</returns>
        public async Task<ApiResult<List<InboundTypeDto>>> Handle(GetInboundTypeListCommand request, CancellationToken cancellationToken)
        {
            try
            {
                // 查询所有入库类型
                var inboundTypes = await _dbContext.InboundType
                    .OrderBy(t => t.Id)
                    .ToListAsync(cancellationToken);

                // 映射为DTO
                var inboundTypeDtos = _mapper.Map<List<InboundTypeDto>>(inboundTypes);

                // 返回成功结果
                return new ApiResult<List<InboundTypeDto>>("获取入库类型列表成功")
                {
                    code = StatusCodeEnum.Ok,
                    data = inboundTypeDtos,
                    isSuc = true
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取入库类型列表失败");
                return new ApiResult<List<InboundTypeDto>>("获取入库类型列表失败：" + ex.Message)
                {
                    code = StatusCodeEnum.Fail,
                    isSuc = false
                };
            }
        }
    }

    /// <summary>
    /// 获取入库单列表命令处理程序
    /// </summary>
    public class GetInboundOrderListCommandHandler : IRequestHandler<GetInboundOrderListCommand, ApiResult<PagingResult<List<InboundOrderDto>>>>
    {
        private readonly MyDBContext _dbContext;
        private readonly IMapper _mapper;
        private readonly ILogger<GetInboundOrderListCommandHandler> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="mapper">对象映射器</param>
        /// <param name="logger">日志记录器</param>
        public GetInboundOrderListCommandHandler(MyDBContext dbContext, IMapper mapper, ILogger<GetInboundOrderListCommandHandler> logger)
        {
            _dbContext = dbContext;
            _mapper = mapper;
            _logger = logger;
        }

        /// <summary>
        /// 处理获取入库单列表命令
        /// </summary>
        /// <param name="request">请求命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>入库单列表分页结果</returns>
        public async Task<ApiResult<PagingResult<List<InboundOrderDto>>>> Handle(GetInboundOrderListCommand request, CancellationToken cancellationToken)
        {
            try
            {
                // 构建查询
                var query = _dbContext.InboundOrder.AsQueryable();

                // 应用筛选条件
                if (request.WarehouseId.HasValue)
                {
                    query = query.Where(o => o.WarehouseId == request.WarehouseId.Value);
                }

                if (request.InboundTypeId.HasValue)
                {
                    query = query.Where(o => o.InboundTypeId == request.InboundTypeId.Value);
                }

                if (!string.IsNullOrEmpty(request.ReferenceNo))
                {
                    query = query.Where(o => o.ReferenceNo1.Contains(request.ReferenceNo) || o.ReferenceNo2.Contains(request.ReferenceNo));
                }

                // 计算总记录数
                var totalCount = await query.CountAsync(cancellationToken);

                // 分页查询
                var inboundOrders = await query
                    .OrderByDescending(o => o.Id)
                    .Skip((request.PageIndex - 1) * request.PageSize)
                    .Take(request.PageSize)
                    .ToListAsync(cancellationToken);

                // 映射为DTO
                var inboundOrderDtos = _mapper.Map<List<InboundOrderDto>>(inboundOrders);

                // 填充仓库名称和入库类型名称
                var warehouseIds = inboundOrderDtos.Select(o => o.WarehouseId).Distinct().ToList();
                var warehouses = await _dbContext.Warehouse
                    .Where(w => warehouseIds.Contains(w.Id))
                    .ToDictionaryAsync(w => w.Id, w => w.WarehouseName, cancellationToken);

                var inboundTypeIds = inboundOrderDtos.Select(o => o.InboundTypeId).Distinct().ToList();
                var inboundTypes = await _dbContext.InboundType
                    .Where(t => inboundTypeIds.Contains(t.Id))
                    .ToDictionaryAsync(t => t.Id, t => t.TypeName, cancellationToken);

                foreach (var dto in inboundOrderDtos)
                {
                    if (warehouses.ContainsKey(dto.WarehouseId))
                    {
                        dto.WarehouseName = warehouses[dto.WarehouseId];
                    }

                    if (inboundTypes.ContainsKey(dto.InboundTypeId))
                    {
                        dto.InboundTypeName = inboundTypes[dto.InboundTypeId];
                    }
                }

                // 构建分页结果
                var pagingResult = new PagingResult<List<InboundOrderDto>>
                {
                    data = inboundOrderDtos,
                    totalCount = totalCount,
                    totalPage = (int)Math.Ceiling(totalCount / (double)request.PageSize)
                };

                // 返回成功结果
                return new ApiResult<PagingResult<List<InboundOrderDto>>>("获取入库单列表成功")
                {
                    code = StatusCodeEnum.Ok,
                    data = pagingResult,
                    isSuc = true
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取入库单列表失败");
                return new ApiResult<PagingResult<List<InboundOrderDto>>>("获取入库单列表失败：" + ex.Message)
                {
                    code = StatusCodeEnum.Fail,
                    isSuc = false
                };
            }
        }
    }

    /// <summary>
    /// 获取入库单详情命令处理程序
    /// </summary>
    public class GetInboundOrderByIdCommandHandler : IRequestHandler<GetInboundOrderByIdCommand, ApiResult<InboundOrderDetailDto>>
    {
        private readonly MyDBContext _dbContext;
        private readonly IMapper _mapper;
        private readonly ILogger<GetInboundOrderByIdCommandHandler> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="mapper">对象映射器</param>
        /// <param name="logger">日志记录器</param>
        public GetInboundOrderByIdCommandHandler(MyDBContext dbContext, IMapper mapper, ILogger<GetInboundOrderByIdCommandHandler> logger)
        {
            _dbContext = dbContext;
            _mapper = mapper;
            _logger = logger;
        }

        /// <summary>
        /// 处理获取入库单详情命令
        /// </summary>
        /// <param name="request">请求命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>入库单详情</returns>
        public async Task<ApiResult<InboundOrderDetailDto>> Handle(GetInboundOrderByIdCommand request, CancellationToken cancellationToken)
        {
            try
            {
                // 查询入库单
                var inboundOrder = await _dbContext.InboundOrder
                    .FirstOrDefaultAsync(o => o.Id == request.Id, cancellationToken);

                if (inboundOrder == null)
                {
                    return new ApiResult<InboundOrderDetailDto>("入库单不存在")
                    {
                        code = StatusCodeEnum.DataNotExist,
                        isSuc = false
                    };
                }

                // 映射为DTO
                var inboundOrderDto = _mapper.Map<InboundOrderDetailDto>(inboundOrder);

                // 查询仓库和入库类型信息
                var warehouse = await _dbContext.Warehouse
                    .FirstOrDefaultAsync(w => w.Id == inboundOrder.WarehouseId, cancellationToken);
                if (warehouse != null)
                {
                    inboundOrderDto.WarehouseName = warehouse.WarehouseName;
                }

                var inboundType = await _dbContext.InboundType
                    .FirstOrDefaultAsync(t => t.Id == inboundOrder.InboundTypeId, cancellationToken);
                if (inboundType != null)
                {
                    inboundOrderDto.InboundTypeName = inboundType.TypeName;
                }

                // 查询入库明细
                var items = await _dbContext.InboundItem
                    .Where(i => i.OrderId == inboundOrder.Id.ToString())
                    .ToListAsync(cancellationToken);
                inboundOrderDto.Items = _mapper.Map<List<InboundItemDto>>(items);

                // 查询产品信息
                var skus = inboundOrderDto.Items.Select(i => i.Sku).Distinct().ToList();
                var products = await _dbContext.Product
                    .Where(p => skus.Contains(p.SKU))
                    .ToDictionaryAsync(p => p.SKU, p => p.ProductName, cancellationToken);

                // 填充商品名称
                foreach (var item in inboundOrderDto.Items)
                {
                    if (products.ContainsKey(item.Sku))
                    {
                        item.ProductName = products[item.Sku];
                    }
                }

                // 查询附件
                var attachments = await _dbContext.InboundAttachment
                    .Where(a => a.OrderId == inboundOrder.Id.ToString())
                    .ToListAsync(cancellationToken);
                inboundOrderDto.Attachments = _mapper.Map<List<InboundAttachmentDto>>(attachments);

                // 返回成功结果
                return new ApiResult<InboundOrderDetailDto>("获取入库单详情成功")
                {
                    code = StatusCodeEnum.Ok,
                    data = inboundOrderDto,
                    isSuc = true
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取入库单详情失败");
                return new ApiResult<InboundOrderDetailDto>("获取入库单详情失败：" + ex.Message)
                {
                    code = StatusCodeEnum.Fail,
                    isSuc = false
                };
            }
        }
    }

    /// <summary>
    /// 创建入库单命令处理程序
    /// </summary>
    public class CreateInboundOrderCommandHandler : IRequestHandler<CreateInboundOrderCommand, ApiResult<int>>
    {
        private readonly MyDBContext _dbContext;
        private readonly IMapper _mapper;
        private readonly ILogger<CreateInboundOrderCommandHandler> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="mapper">对象映射器</param>
        /// <param name="logger">日志记录器</param>
        public CreateInboundOrderCommandHandler(MyDBContext dbContext, IMapper mapper, ILogger<CreateInboundOrderCommandHandler> logger)
        {
            _dbContext = dbContext;
            _mapper = mapper;
            _logger = logger;
        }

        /// <summary>
        /// 处理创建入库单命令
        /// </summary>
        /// <param name="request">请求命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>创建结果</returns>
        public async Task<ApiResult<int>> Handle(CreateInboundOrderCommand request, CancellationToken cancellationToken)
        {
            using var transaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);
            try
            {
                // 检查仓库是否存在
                var warehouse = await _dbContext.Warehouse
                    .FirstOrDefaultAsync(w => w.Id == request.InboundOrder.WarehouseId, cancellationToken);
                if (warehouse == null)
                {
                    return new ApiResult<int>("仓库不存在")
                    {
                        code = StatusCodeEnum.DataNotExist,
                        isSuc = false
                    };
                }

                // 检查入库类型是否存在
                var inboundType = await _dbContext.InboundType
                    .FirstOrDefaultAsync(t => t.Id == request.InboundOrder.InboundTypeId, cancellationToken);
                if (inboundType == null)
                {
                    return new ApiResult<int>("入库类型不存在")
                    {
                        code = StatusCodeEnum.DataNotExist,
                        isSuc = false
                    };
                }

                // 映射为实体
                var inboundOrder = _mapper.Map<InboundOrder>(request.InboundOrder);
                inboundOrder.CreateTime = DateTime.Now;

                // 添加入库单
                _dbContext.InboundOrder.Add(inboundOrder);
                await _dbContext.SaveChangesAsync(cancellationToken);

                // 添加入库明细
                if (request.InboundOrder.Items != null && request.InboundOrder.Items.Any())
                {
                    foreach (var itemDto in request.InboundOrder.Items)
                    {
                        var item = _mapper.Map<InboundItem>(itemDto);
                        item.OrderId = inboundOrder.Id.ToString();
                        _dbContext.InboundItem.Add(item);
                    }
                    await _dbContext.SaveChangesAsync(cancellationToken);
                }

                await transaction.CommitAsync(cancellationToken);

                // 返回成功结果
                return new ApiResult<int>("创建入库单成功")
                {
                    code = StatusCodeEnum.Ok,
                    data = inboundOrder.Id,
                    isSuc = true
                };
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync(cancellationToken);
                _logger.LogError(ex, "创建入库单失败");
                return new ApiResult<int>("创建入库单失败：" + ex.Message)
                {
                    code = StatusCodeEnum.Fail,
                    isSuc = false
                };
            }
        }
    }

    /// <summary>
    /// 更新入库单命令处理程序
    /// </summary>
    public class UpdateInboundOrderCommandHandler : IRequestHandler<UpdateInboundOrderCommand, ApiResult<int>>
    {
        private readonly MyDBContext _dbContext;
        private readonly IMapper _mapper;
        private readonly ILogger<UpdateInboundOrderCommandHandler> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="mapper">对象映射器</param>
        /// <param name="logger">日志记录器</param>
        public UpdateInboundOrderCommandHandler(MyDBContext dbContext, IMapper mapper, ILogger<UpdateInboundOrderCommandHandler> logger)
        {
            _dbContext = dbContext;
            _mapper = mapper;
            _logger = logger;
        }

        /// <summary>
        /// 处理更新入库单命令
        /// </summary>
        /// <param name="request">请求命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>更新结果</returns>
        public async Task<ApiResult<int>> Handle(UpdateInboundOrderCommand request, CancellationToken cancellationToken)
        {
            using var transaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);
            try
            {
                // 查询入库单
                var inboundOrder = await _dbContext.InboundOrder
                    .FirstOrDefaultAsync(o => o.Id == request.InboundOrder.Id, cancellationToken);
                if (inboundOrder == null)
                {
                    return new ApiResult<int>("入库单不存在")
                    {
                        code = StatusCodeEnum.DataNotExist,
                        isSuc = false
                    };
                }

                // 检查仓库是否存在
                var warehouse = await _dbContext.Warehouse
                    .FirstOrDefaultAsync(w => w.Id == request.InboundOrder.WarehouseId, cancellationToken);
                if (warehouse == null)
                {
                    return new ApiResult<int>("仓库不存在")
                    {
                        code = StatusCodeEnum.DataNotExist,
                        isSuc = false
                    };
                }

                // 检查入库类型是否存在
                var inboundType = await _dbContext.InboundType
                    .FirstOrDefaultAsync(t => t.Id == request.InboundOrder.InboundTypeId, cancellationToken);
                if (inboundType == null)
                {
                    return new ApiResult<int>("入库类型不存在")
                    {
                        code = StatusCodeEnum.DataNotExist,
                        isSuc = false
                    };
                }

                // 更新入库单
                inboundOrder.WarehouseId = request.InboundOrder.WarehouseId;
                inboundOrder.InboundTypeId = request.InboundOrder.InboundTypeId;
                inboundOrder.Volume = request.InboundOrder.Volume;
                inboundOrder.EstimatedArrivalTime = request.InboundOrder.EstimatedArrivalTime;
                inboundOrder.PortDepartureTime = request.InboundOrder.PortDepartureTime;
                inboundOrder.PortArrivalTime = request.InboundOrder.PortArrivalTime;
                inboundOrder.ReferenceNo1 = request.InboundOrder.ReferenceNo1;
                inboundOrder.ReferenceNo2 = request.InboundOrder.ReferenceNo2;

                await _dbContext.SaveChangesAsync(cancellationToken);

                // 更新入库明细
                if (request.InboundOrder.Items != null && request.InboundOrder.Items.Any())
                {
                    // 删除旧的明细
                    var oldItems = await _dbContext.InboundItem
                        .Where(i => i.OrderId == inboundOrder.Id.ToString())
                        .ToListAsync(cancellationToken);
                    _dbContext.InboundItem.RemoveRange(oldItems);

                    // 添加新的明细
                    foreach (var itemDto in request.InboundOrder.Items)
                    {
                        var item = _mapper.Map<InboundItem>(itemDto);
                        item.OrderId = inboundOrder.Id.ToString();
                        _dbContext.InboundItem.Add(item);
                    }

                    await _dbContext.SaveChangesAsync(cancellationToken);
                }

                await transaction.CommitAsync(cancellationToken);

                // 返回成功结果
                return new ApiResult<int>("更新入库单成功")
                {
                    code = StatusCodeEnum.Ok,
                    data = inboundOrder.Id,
                    isSuc = true
                };
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync(cancellationToken);
                _logger.LogError(ex, "更新入库单失败");
                return new ApiResult<int>("更新入库单失败：" + ex.Message)
                {
                    code = StatusCodeEnum.Fail,
                    isSuc = false
                };
            }
        }
    }

    /// <summary>
    /// 删除入库单命令处理程序
    /// </summary>
    public class DeleteInboundOrderCommandHandler : IRequestHandler<DeleteInboundOrderCommand, ApiResult<int>>
    {
        private readonly MyDBContext _dbContext;
        private readonly ILogger<DeleteInboundOrderCommandHandler> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="logger">日志记录器</param>
        public DeleteInboundOrderCommandHandler(MyDBContext dbContext, ILogger<DeleteInboundOrderCommandHandler> logger)
        {
            _dbContext = dbContext;
            _logger = logger;
        }

        /// <summary>
        /// 处理删除入库单命令
        /// </summary>
        /// <param name="request">请求命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>删除结果</returns>
        public async Task<ApiResult<int>> Handle(DeleteInboundOrderCommand request, CancellationToken cancellationToken)
        {
            using var transaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);
            try
            {
                // 查询入库单
                var inboundOrder = await _dbContext.InboundOrder
                    .FirstOrDefaultAsync(o => o.Id == request.Id, cancellationToken);
                if (inboundOrder == null)
                {
                    return new ApiResult<int>("入库单不存在")
                    {
                        code = StatusCodeEnum.DataNotExist,
                        isSuc = false
                    };
                }

                // 删除入库明细
                var items = await _dbContext.InboundItem
                    .Where(i => i.OrderId == inboundOrder.Id.ToString())
                    .ToListAsync(cancellationToken);
                _dbContext.InboundItem.RemoveRange(items);

                // 删除附件
                var attachments = await _dbContext.InboundAttachment
                    .Where(a => a.OrderId == inboundOrder.Id.ToString())
                    .ToListAsync(cancellationToken);
                _dbContext.InboundAttachment.RemoveRange(attachments);

                // 删除入库单
                _dbContext.InboundOrder.Remove(inboundOrder);

                await _dbContext.SaveChangesAsync(cancellationToken);
                await transaction.CommitAsync(cancellationToken);

                // 返回成功结果
                return new ApiResult<int>("删除入库单成功")
                {
                    code = StatusCodeEnum.Ok,
                    data = request.Id,
                    isSuc = true
                };
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync(cancellationToken);
                _logger.LogError(ex, "删除入库单失败");
                return new ApiResult<int>("删除入库单失败：" + ex.Message)
                {
                    code = StatusCodeEnum.Fail,
                    isSuc = false
                };
            }
        }
    }

    /// <summary>
    /// 上传入库单附件命令处理程序
    /// </summary>
    public class UploadInboundAttachmentCommandHandler : IRequestHandler<UploadInboundAttachmentCommand, ApiResult<string>>
    {
        private readonly MyDBContext _dbContext;
        private readonly IWebHostEnvironment _hostingEnvironment;
        private readonly ILogger<UploadInboundAttachmentCommandHandler> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="hostingEnvironment">Web主机环境</param>
        /// <param name="logger">日志记录器</param>
        public UploadInboundAttachmentCommandHandler(
            MyDBContext dbContext, 
            IWebHostEnvironment hostingEnvironment,
            ILogger<UploadInboundAttachmentCommandHandler> logger)
        {
            _dbContext = dbContext;
            _hostingEnvironment = hostingEnvironment;
            _logger = logger;
        }

        /// <summary>
        /// 处理上传入库单附件命令
        /// </summary>
        /// <param name="request">请求命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>上传结果</returns>
        public async Task<ApiResult<string>> Handle(UploadInboundAttachmentCommand request, CancellationToken cancellationToken)
        {
            try
            {
                // 检查入库单是否存在
                var inboundOrder = await _dbContext.InboundOrder
                    .FirstOrDefaultAsync(o => o.Id == request.InboundOrderId, cancellationToken);
                if (inboundOrder == null)
                {
                    return new ApiResult<string>("入库单不存在")
                    {
                        code = StatusCodeEnum.DataNotExist,
                        isSuc = false
                    };
                }

                // 检查文件
                if (request.File == null || request.File.Length == 0)
                {
                    return new ApiResult<string>("请选择文件")
                    {
                        code = StatusCodeEnum.ParamError,
                        isSuc = false
                    };
                }

                // 保存文件
                var uploadsFolder = Path.Combine(_hostingEnvironment.WebRootPath, "Inbound");
                if (!Directory.Exists(uploadsFolder))
                {
                    Directory.CreateDirectory(uploadsFolder);
                }

                var fileName = Guid.NewGuid().ToString() + Path.GetExtension(request.File.FileName);
                var filePath = Path.Combine(uploadsFolder, fileName);

                using (var fileStream = new FileStream(filePath, FileMode.Create))
                {
                    await request.File.CopyToAsync(fileStream, cancellationToken);
                }

                // 保存附件记录
                var attachment = new InboundAttachment
                {
                    OrderId = inboundOrder.Id.ToString(),
                    AttachmentType = request.AttachmentType,
                    FilePath = "/Inbound/" + fileName,
                    UploadStatus = "已上传"
                };

                _dbContext.InboundAttachment.Add(attachment);
                await _dbContext.SaveChangesAsync(cancellationToken);

                // 返回成功结果
                return new ApiResult<string>("上传附件成功")
                {
                    code = StatusCodeEnum.Ok,
                    data = attachment.FilePath,
                    isSuc = true
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "上传附件失败");
                return new ApiResult<string>("上传附件失败：" + ex.Message)
                {
                    code = StatusCodeEnum.Fail,
                    isSuc = false
                };
            }
        }
    }
} 